/*
 * Package il.ac.biu.cs.grossmm.impl.activeData
 * File MemInspector.java
 * 
 * This is a part of presence service framework prototype. 
 * See javadoc for more information.
 *  
 * Copyright (C) 2006 Grossmann Mark
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.

 * You should have received a copy of the GNU Lesser General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 */
package il.ac.biu.cs.grossmm.impl.activeData;

import java.util.Set;

import il.ac.biu.cs.grossmm.api.OperationFailedException;
import il.ac.biu.cs.grossmm.api.data.*;
import il.ac.biu.cs.grossmm.api.flow.NodeInspector;

@SuppressWarnings("unchecked")
public class MemInspector implements NodeInspector {
	final int epoch;

	static final MemInspector INSTANCE = new MemInspector(0);

	public MemInspector(int epoch) {
		this.epoch = epoch;
	}

	public <N, S> Set<Node<S>> getSubnodes(Node<N> nod, Nodeset<N, S> nods) {
		MemNode<N> node = (MemNode<N>) nod;

		int index = nods.index();
		return getSubnodes(node, index);
	}

	/**
	 * @param <N>
	 * @param node
	 * @param index
	 * @return
	 */
	protected <N, S> Set<Node<S>> getSubnodes(MemNode<N> node, int index) {
		return node.getSubnodes(index, epoch);
	}

	public <N, P> P getValue(Node<N> nod, Property<N, P> property) {
		MemNode<N> node = (MemNode<N>) nod;

		return (P) node.getValue(property, epoch + 1);
	}

	public <N> UpdateType getUpdateType(Node<N> nod) {
		MemNode<N> node = (MemNode<N>) nod;
		return node.getUpdateType(epoch);
	}

	public <N, S, U> MemNode<S> getSubnode(Node<N> node, Nodeset<N, S> nodeSet,
			Unique<S, U> unique, U value) {
		int index = unique.index();

		Set<HashedNode<S>> set = (Set) getSubnodes(node, nodeSet);

		for (MemNode<S> n : set) {
			Object val = n.getValue(index, epoch + 1);
			if (val == null)
				continue;
			if (val.equals(value))
				return n;
		}

		return null;
	}

	/**
	 * @param <S>
	 * @param <U>
	 * @param <N>
	 * @param node
	 * @param nodeSet
	 * @param value
	 * @param index
	 * @return
	 */
	protected <S, U, N> MemNode<S> getSubnode(MemNode<N> node, int index,
			Unique<S, U> unique, U value) {
		Set<HashedNode<S>> set = (Set) getSubnodes(node, index);

		for (MemNode<S> n : set) {
			Object val = n.getValue(index, epoch + 1);
			if (val == null)
				continue;
			if (val.equals(value))
				return n;
		}

		return null;
	}

	private void toStringBuffer(Node node, StringBuffer sb, String prefix)
			throws OperationFailedException {
		NodeType type = node.getNodeType();

		int numOfProps = type.propertiesNumber();

		for (int i = 0; i < numOfProps; i++) {
			Property property = type.property(i);
			Object value = getValue(node, property);
			sb.append(prefix);
			sb.append(property);
			sb.append(" = ");
			sb.append(value);
			sb.append("\n");
		}

		int numOfSets = type.nodesetsNumber();

		String prefix2 = prefix + "   ";

		for (int i = 0; i < numOfSets; i++) {
			Nodeset nodeset = type.nodeset(i);
			Set<Node> subnodes = getSubnodes(node, nodeset);

			sb.append(prefix);
			sb.append(nodeset);
			sb.append(" = {\n");

			int j = 0;
			for (Node n : subnodes) {
				if (j++ > 0)
					sb.append('\n');
				toStringBuffer(n, sb, prefix2);
			}

			sb.append(prefix).append("}\n");
		}
	}

	public String toString(Node node) {
		StringBuffer sb = new StringBuffer("\n");
		try {
			toStringBuffer(node, sb, "");
		} catch (OperationFailedException e) {
			return "[[" + e.getMessage() + "]]";
		}

		return sb.toString();
	}
}
